package easycloud.ecs.server.service;

import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Inject;

import org.apache.commons.lang.reflect.ConstructorUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import easycloud.ecs.common.domain.Item;
import easycloud.ecs.common.domain.Item.ITEM_STATUS;
import easycloud.ecs.common.domain.Provider;
import easycloud.ecs.common.repository.HashRepository;
import easycloud.ecs.common.repository.ItemRepository;
import easycloud.ecs.common.service.ItemService;
import easycloud.ecs.provider.api.IProvider;
import easycloud.ecs.provider.model.IStorageObjectMetadata;

@Service
@Transactional(readOnly = true)
public class ItemServiceImpl implements ItemService {

	private static final Log logger = LogFactory.getLog(ItemServiceImpl.class);

	@Inject
	private ItemRepository itemRepository;

	@Inject
	private HashRepository hashRepository;

	private Map<String,IProvider> providers = new HashMap<String,IProvider>();

	@Override
	public Item getItem(String path, Provider provider) {
		return itemRepository.findByPath(path, provider);
	}

	@Override
	public Map<String, Item> getItems(Collection<String> paths,
			Provider provider) {
		Map<String, Item> result = new HashMap<String, Item>();
		for (String path : paths) {
			Item item = getItem(path, provider);
			if (item != null) {
				result.put(path, item);
			}
		}
		return result;
	}

	public Map<String, Item> getItems(Provider provider) {
		Map<String, Item> result = new HashMap<String, Item>();
		List<Item> items = itemRepository.findByProvider(provider);
		for (Item item : items) {
			result.put(item.getPath(), item);
		}
		return result;
	}

	@Override
	@Transactional(readOnly = false)
	public void updateServer(List<IStorageObjectMetadata> localItems) {
		logger.debug("updateServer");
		for (IStorageObjectMetadata meta : localItems) {
			if (meta.getItem().getStatus() == ITEM_STATUS.LOCAL_DELETE) {
				meta.getItem().setIsDelete(true);
				itemRepository.save(meta.getItem());
			} else {
				itemRepository.save(meta.getItem());
				hashRepository.save(meta.getItem().getHashs());
			}
		}
	}

	@Override
	@Transactional(readOnly = false)
	public List<Item> updateConflict(List<IStorageObjectMetadata> conflictItems) {
		logger.debug("updateConflict");
		List<Item> result = new ArrayList<Item>();
		for (IStorageObjectMetadata meta : conflictItems) {
			Item localItem = new Item();
			localItem.setCreateProvider(meta.getItem().getUpdateProvider());
			localItem.setCreateTick(meta.getItem().getUpdateTick());
			localItem.setFolder(meta.getItem().getFolder());
			localItem.setHashs(meta.getItem().getHashs());
			localItem.setLastModified(meta.getLastModified());
			localItem.setLength(meta.getLength());
			localItem.setPath(meta.getPath() + "."
					+ meta.getItem().getUpdateProvider().getName());
			localItem.setUpdateProvider(meta.getItem().getUpdateProvider());
			localItem.setUpdateTick(meta.getItem().getUpdateTick());

			Item remoteOriginalItem = itemRepository.findOne(meta.getItem()
					.getId());
			remoteOriginalItem.setPath(remoteOriginalItem.getPath() + "."
					+ remoteOriginalItem.getUpdateProvider().getName());

			itemRepository.save(localItem);
			hashRepository.save(localItem.getHashs());
			itemRepository.save(remoteOriginalItem);
			result.add(localItem);
		}
		return result;
	}

	@Override
	public URL getAccessURL(Provider provider, Item item) {
		if (!providers.containsKey(provider.getName())) {
			try {
				Class providerClass = Class.forName(provider.getClassName());
				IProvider providerImpl = (IProvider) ConstructorUtils
						.invokeConstructor(providerClass, provider);
				providers.put(provider.getName(),providerImpl);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			}
		}
		IProvider providerImpl = providers.get(provider.getName());
		URL url = providerImpl.getAccessURL(item);
		return url;
	}
}
